package com.ms.game.slot.base;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.utility.GameUtility;

public class SlotScreenSymbol<T>{
	/** log4j object */
	private static final Log log = LogFactory.getLog("com.ms.game.slot.base.SlotScreenSymbol");
	
	/**
	 * 排列帶 - 橫式
	 */
	public static final int TYPE_ARRANGE = 1;
	
	/**
	 * 非排列帶
	 */
	public static final int TYPE_NO_ARRANGE = 2;
	
	/**
	 * 排列帶 - 直式
	 */
	public static final int TYPE_ARRANGE_STRAIGHT = 3;
	
	/**
	 * 排列帶 - 群組直式<br>
	 * 兩輪為一群組
	 */
	public static final int TYPE_ARRANGE_STRAIGHT_GROUP_2 = 10;
	
	
	
	private SecureRandom  random = new SecureRandom();
	
	
	private ArrayList<Integer> wheelStartIdx = null;
	
	
	public ArrayList<Integer> getWheelStartIdx() {
		return wheelStartIdx;
	}

	public void setWheelStartIdx(ArrayList<Integer> wheelStartIdx) {
		this.wheelStartIdx = wheelStartIdx;
	}



	/**
	 * 配合企劃需求，記錄某輪idx
	 */
	private int wheelIdx =-1;
	
	
	public int getWheelIdx() {
		return wheelIdx;
	}

	public void setWheelIdx(int wheelIdx) {
		this.wheelIdx = wheelIdx;
	}

	public ArrayList<Integer> getScreenSymbol(int type , int row , int col  , T robbin )
	{
		ArrayList<Integer> list = null;
		switch(type)
		{
			case TYPE_ARRANGE:
			{
				list = getArrange(row , col , robbin);
			}break;
			case TYPE_NO_ARRANGE:
			{
				list = getNoArrange(row*col  , robbin);
			}break;
			case TYPE_ARRANGE_STRAIGHT:
			{
				list = this.getArrangeStraight(row , col , robbin);
			}break;
			case TYPE_ARRANGE_STRAIGHT_GROUP_2:
			{
				list = getArrangeGroupStraight(row , col , robbin, 2);
			}break;
		}
		return list;
	}
	
	/**
	 * 使用直式排列帶取得指定排列帶範圍的圖形
	 * 
	 * @param row
	 *            每個排列帶要取出的圖形數量
	 * @param startcol
	 *            從第幾個排列帶開始取 (0 base)
	 * @param endcol
	 *            取到第幾個排列到結束 (0 base)
	 * @param robbin
	 * @return
	 */
	public ArrayList<Integer> getScreenSymbolByColRange(int row, int startcol, int endcol, T robbin)
	{
		ArrayList<Integer> list = null;
		
		list = this.getArrangeStraightByColRange(row, startcol, endcol, robbin);

		return list;
	}
	
	/**
	 * 先算出指定範圍輪的Symbol </br>
	 * 並且替換到原始盤面所在位置 </br>
	 * 
	 * @param orgScreen 原始盤面
	 * @param row 幾列
	 * @param startcol 第幾輪開始要換 
	 * @param endcol 結束的輪
	 * @param robbin 排列帶
	 * @return
	 */
	public ArrayList<Integer> getReplacedScreenSymbolByColRange(ArrayList<Integer> orgScreen, int row, int startcol, int endcol, T robbin) {
		ArrayList<Integer> list = this.getArrangeStraightByColRange(row, startcol, endcol, robbin);
		
		list = replaceWheelScreen(orgScreen, row, startcol, endcol, list);
		
		return list;
	}
	
	
	/**
	 * 更新要替換的盤面
	 * @return
	 */
	private ArrayList<Integer> replaceWheelScreen(ArrayList<Integer> screen, int row, int startCol, int endCol, ArrayList<Integer> wheelScreen){
		// 算出幾到幾symbo
		int from = row * startCol;
		int end = row * (endCol + 1);
		
		//要被替換掉的輪 ， endCol + 1 是因為 sublist 是 大於from 小於 end
		List<Integer> changeRow = screen.subList(from, end);
		
		//跑迴圈換掉
		for (int i = 0; i < wheelScreen.size(); i++) {
			changeRow.set(i, wheelScreen.get(i));
		}
		
		return screen;
	}
	
	/**
	 * 先算出指定輪的Symbol </br>
	 * 並且替換到原始盤面所在位置 </br>
	 * @param orgScreen 原始盤面
	 * @param row 列
	 * @param cols 指定的輪
	 * @param robbin 排列帶
	 * @return
	 */
	public ArrayList<Integer> getReplacedScreenSymbolByAppointedCol(ArrayList<Integer> orgScreen, int row, ArrayList<Integer> cols, T robbin) {
		ArrayList<Integer> list = new ArrayList<Integer>();
		for (Integer col : cols) {
			list = getReplacedScreenSymbolByColRange(new ArrayList<Integer>(orgScreen), row, col, col, robbin);
		}
		return list;
	}	
	
	/**
	 * 排列帶 - 橫式
	 * @param col
	 * @param row
	 * @param robbin
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<Integer> getArrange(int row , int col , T robbin)
	{
		ArrayList<Integer> finalscreen = new ArrayList<Integer> (row*col);
		Integer [] screen = new Integer[row*col];
		
		//System.out.println("Horse Screen1 = " + Arrays.toString(screen) );
		ArrayList<Integer> wheelidx =  new ArrayList<Integer>();
		for(int i=0;i<col;i++)
		{
			Method exec=null;
			wheelidx.clear();
			try 
			{
				exec = robbin.getClass().getMethod("getWheel"+i,  new Class[0]);
				ArrayList<Integer> list = (ArrayList<Integer>) exec.invoke(robbin, new Object[]{});
				
				//第一輪位置
				for(int j=0;j<row;j++)
				{
					wheelidx.add(i+(j*col));
				}
				
				ArrayList<Integer> temp = new ArrayList<Integer>();
				int startidx = randIndex(list.size());
				for(int k=0;k<wheelidx.size();k++)
				{
					int symbol =list.get(startidx);
					temp.add(startidx);
					
					startidx++;
					if(startidx >= list.size())
					{
						startidx = 0;
					}
					screen[wheelidx.get(k)] = symbol;
				}
				//System.out.println("Horse Screen = " + Arrays.toString(screen) );
				//System.out.println("Horse IDX = " + Arrays.toString(temp.toArray()) );
				//System.out.println("Horse getWheel"+i+" = " + Arrays.toString(list.toArray()) );
			} 
			catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
			{
				e.printStackTrace();
			}	
		}
		
		//System.out.println("Horse Screen3 = " + Arrays.toString(screen) );
		List<Integer> ss = Arrays.asList(screen);
		finalscreen.addAll(ss);
		return finalscreen;
	}
	
	
	/**
	 * 非排列帶
	 * @param col
	 * @param row
	 * @param robbin
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<Integer> getNoArrange(int totalsize , T robbin)
	{
		ArrayList<Integer> screen = new ArrayList<Integer> (totalsize);
		for(int i=0;i<totalsize;i++)
		{
			Method exec;
			try 
			{
				exec = robbin.getClass().getMethod("getWheel"+i,  new Class[0]);
				ArrayList<Integer> list = (ArrayList<Integer>) exec.invoke(robbin, new Object[]{});
				
				int idx = randIndex(list.size());
				
				screen.add(list.get(idx));
			}
			catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
			{
				e.printStackTrace();
			}
		}
		return screen;
	}
	
	/**
	 * 排列帶 - 直式
	 * @param col
	 * @param row
	 * @param robbin
	 * @return
	 */
	private ArrayList<Integer> getArrangeStraight(int row , int col , T robbin)
	{
		ArrayList<Integer> finalscreen = new ArrayList<Integer> (row*col);
		Integer [] screen = new Integer[row*col];
		
		//System.out.println("Horse Screen1 = " + Arrays.toString(screen) );
		
		wheelStartIdx = new  ArrayList<Integer>();
		ArrayList<Integer> wheelidx =  new ArrayList<Integer>();
		for(int i=0;i<col;i++)
		{
			Method exec=null;
			wheelidx.clear();
			try 
			{
				exec = robbin.getClass().getMethod("getWheel"+i,  new Class[0]);
				ArrayList<Integer> list = (ArrayList<Integer>) exec.invoke(robbin, new Object[]{});
				
				//第一輪位置
				for(int j=0;j<row;j++)
				{
					wheelidx.add(i*row+j);
				}
				
				ArrayList<Integer> temp = new ArrayList<Integer>();
				int startidx = randIndex(list.size());
				
				//儲存排列帶起始位置
				wheelStartIdx.add(startidx);
				
				
				for(int k=0;k<wheelidx.size();k++)
				{
					int symbol =list.get(startidx);
					temp.add(startidx);
					
					startidx++;
					if(startidx >= list.size())
					{
						startidx = 0;
					}
					screen[wheelidx.get(k)] = symbol;
				}
				//System.out.println("Horse Screen = " + Arrays.toString(screen) );
				//System.out.println("Horse IDX = " + Arrays.toString(temp.toArray()) );
				//System.out.println("Horse getWheel"+i+" = " + Arrays.toString(list.toArray()) );
			} 
			catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
			{
				e.printStackTrace();
			}	
		}
		
		List<Integer> ss = Arrays.asList(screen);
		finalscreen.addAll(ss);
		return finalscreen;
	}
	
	/**
	 * 排列帶 - 直式群組(如果同一群組的排列帶不一樣長，會以第一個排列帶為主)
	 * @param row
	 * @param col
	 * @param robbin
	 * @param groupCol 以多少輪為一個群組(運用同一個startIDX)
	 * @return
	 */
	private ArrayList<Integer> getArrangeGroupStraight(int row, int col, T robbin, int groupCol) {
		ArrayList<Integer> finalscreen = new ArrayList<Integer>(row * col);
		Integer[] screen = new Integer[row * col];

		//當前的起始index
		int currentGroupStartIDX = 0;

		wheelStartIdx = new ArrayList<Integer>();
		
		ArrayList<Integer> wheelidx = new ArrayList<Integer>();
		for (int i = 0; i < col; i++) {
			
			Method exec = null;
			wheelidx.clear();
			
			try {
				
				exec = robbin.getClass().getMethod("getWheel" + i, new Class[0]);
				ArrayList<Integer> list = (ArrayList<Integer>) exec.invoke(robbin, new Object[] {});

				// 該輪的symbol位置
				for (int j = 0; j < row; j++) {
					wheelidx.add(i * row + j);
				}

				// 新的一個群組
				if (i % groupCol == 0) {
					currentGroupStartIDX = randIndex(list.size());
				}
				
				int startIDX = currentGroupStartIDX;

				for (int k = 0; k < wheelidx.size(); k++) {
					int symbol = list.get(startIDX);

					startIDX++;
					
					if (startIDX >= list.size()) {
						startIDX = 0;
					}
					
					screen[wheelidx.get(k)] = symbol;
				}
				
			} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				e.printStackTrace();
			}
			
		}

		List<Integer> ss = Arrays.asList(screen);
		finalscreen.addAll(ss);
		return finalscreen;
	}
	
	/**
	 * 排列帶 - 直式, 可指定排列帶範圍
	 * 
	 * @param row
	 *            每個排列帶要取出的圖形數量
	 * @param startcol
	 *            從第幾個排列帶開始取 (0 base)
	 * @param endcol
	 *            取到第幾個排列到結束 (0 base)
	 * @param robbin
	 * @return
	 */
	private ArrayList<Integer> getArrangeStraightByColRange(int row , int startcol , int endcol , T robbin)
	{
		// 排列帶數量
//		int colCnt = endcol - startcol + 1;
		// 輸出資料陣列長度
//		int dataLen = row * colCnt;
		
		ArrayList<Integer> finalscreen = new ArrayList<Integer>();
//		Integer[] screen = new Integer[ row * (endcol + 1)];
		
		ArrayList<Integer> wheelidx =  new ArrayList<Integer>();
		for (int i = startcol; i <= endcol; i++)
		{
			Method exec=null;
			wheelidx.clear();
			try 
			{
				exec = robbin.getClass().getMethod("getWheel" + i, new Class[0]);
				@SuppressWarnings("unchecked")
				ArrayList<Integer> list = (ArrayList<Integer>) exec.invoke(robbin, new Object[]{});
				
				//第一輪位置
				for (int j = 0; j < row; j++) {
					wheelidx.add(i * row + j);
				}
				
//				ArrayList<Integer> temp = new ArrayList<Integer>();
				int startidx = randIndex(list.size());
				for (int k = 0; k < wheelidx.size(); k++) {
					int symbol =list.get(startidx);
//					temp.add(startidx);
					
					startidx++;
					if (startidx >= list.size()) {
						startidx = 0;
					}
//					screen[wheelidx.get(k)] = symbol;
					
					finalscreen.add(symbol);
				}

			} 
			catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
			{
				if (log.isErrorEnabled()) {
					log.error("", e);
				}
			}	
		}
		
//		List<Integer> ss = Arrays.asList(screen);
//		finalscreen.addAll(ss.subList(row * startcol , row * (endcol + 1)));
		return finalscreen;
	}

	/**
	 * 隨機參數讀取位置
	 * @param size
	 * @return
	 */
	private int randIndex(int size)
	{
		int idx = 0;
		int rand  = GameUtility.randomInt(1,100);
		if(rand ==0 || rand%2==0)
		{
				if(size==1)
				{
					size = 1;
				}
				
				idx=(GameUtility.randomInt(1,1000000) +random.nextInt(99999999) + GameUtility.randomInt(size,99999999))%size;
		}
		else
		{
				idx= GameUtility.randomInt(0,size-1);
		}
		
		return idx;
	}
	
	public ArrayList<Integer> getScreenSymbolByWheelIDX(int type , int row , int col  , T robbin , int recordwheelidx)
	{
		ArrayList<Integer> list = null;
		switch(type)
		{
			case TYPE_ARRANGE:
			{
				list = getArrangeX(row , col , robbin,recordwheelidx);
			}break;
			case TYPE_NO_ARRANGE:
			{
				list = getNoArrangeX(row*col  , robbin,recordwheelidx);
			}break;
		}
		return list;
	}
	
	/**
	 * 排列帶
	 * @param col
	 * @param row
	 * @param robbin
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<Integer> getArrangeX(int row , int col , T robbin,int recordwheelidx)
	{
		ArrayList<Integer> finalscreen = new ArrayList<Integer> (row*col);
		Integer [] screen = new Integer[row*col];
		
		//System.out.println("Horse Screen1 = " + Arrays.toString(screen) );
		ArrayList<Integer> wheelidx =  new ArrayList<Integer>();
		for(int i=0;i<col;i++)
		{
			Method exec=null;
			wheelidx.clear();
			try 
			{
				exec = robbin.getClass().getMethod("getWheel"+i,  new Class[0]);
				ArrayList<Integer> list = (ArrayList<Integer>) exec.invoke(robbin, new Object[]{});
				
				//第一輪位置
				for(int j=0;j<row;j++)
				{
					wheelidx.add(i+(j*col));
				}
				
				ArrayList<Integer> temp = new ArrayList<Integer>();
				int startidx = randIndex(list.size());
				
				
				//記錄指定輪本盤的idx
				if(recordwheelidx == i)
				{
					this.wheelIdx = startidx;
				}
				
				for(int k=0;k<wheelidx.size();k++)
				{
					int symbol =list.get(startidx);
					temp.add(startidx);
					
					startidx++;
					if(startidx >= list.size())
					{
						startidx = 0;
					}
					screen[wheelidx.get(k)] = symbol;
				}
				//System.out.println("Horse Screen = " + Arrays.toString(screen) );
				//System.out.println("Horse IDX = " + Arrays.toString(temp.toArray()) );
				//System.out.println("Horse getWheel"+i+" = " + Arrays.toString(list.toArray()) );
			} 
			catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
			{
				e.printStackTrace();
			}	
		}
		
		//System.out.println("Horse Screen3 = " + Arrays.toString(screen) );
		List<Integer> ss = Arrays.asList(screen);
		finalscreen.addAll(ss);
		return finalscreen;
	}
	
	
	/**
	 * 非排列帶
	 * @param col
	 * @param row
	 * @param robbin
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private ArrayList<Integer> getNoArrangeX(int totalsize , T robbin,int recordwheelidx)
	{
		ArrayList<Integer> screen = new ArrayList<Integer> (totalsize);
		for(int i=0;i<totalsize;i++)
		{
			Method exec;
			try 
			{
				exec = robbin.getClass().getMethod("getWheel"+i,  new Class[0]);
				ArrayList<Integer> list = (ArrayList<Integer>) exec.invoke(robbin, new Object[]{});
				
				int idx = randIndex(list.size());
				
				//記錄指定輪本盤的idx
				if(recordwheelidx == i)
				{
					this.wheelIdx = idx;
				}
				
				screen.add(list.get(idx));
			}
			catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 
			{
				e.printStackTrace();
			}
		}
		return screen;
	}
}
